const isFunction = (f) => typeof f === "function";
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class MyPromise {
  constructor(executor) {
    if (!isFunction(executor)) {
      throw new Error("MyPromise must accept a function as a parameter");
    }
    this._status = PENDING;
    this._value = undefined;
    this._fulfilledQueues = [];
    this._rejectedQueues = [];

    try {
      executor(this._resolve.bind(this), this._reject.bind(this));
    } catch (err) {
      this._reject(err);
    }
  }

  _resolve(value) {
    queueMicrotask(() => {
      if (this._status !== PENDING) return;

      if (value instanceof MyPromise) {
        value.then(
          (v) => {
            this._value = v;
            this._status = FULFILLED;
            this._fulfilledQueues.forEach((cb) => cb(value));
          },
          (reason) => {
            this._value = reason;
            this._status = REJECTED;
            this._rejectedQueues.forEach((cb) => cb(reason));
          }
        );
      } else {
        this._status = FULFILLED;
        this._value = value;
        this._fulfilledQueues.forEach((cb) => cb(value));
      }
    });
  }

  _reject(reason) {
    if (this._status !== PENDING) return;
    queueMicrotask(() => {
      this._status = REJECTED;
      this._value = reason;
      this._rejectedQueues.forEach((cb) => cb(reason));
    });
  }

  then(
    onFulfilled = (v) => v,
    onRejected = (e) => {
      throw e;
    }
  ) {
    return new MyPromise((resolve, reject) => {
      // 封装一个成功时执行的函数
      const fulfilled = (value) => {
        try {
          if (!isFunction(onFulfilled)) {
            resolve(value);
          } else {
            let x = onFulfilled(value);
            if (x instanceof MyPromise) {
              x.then(resolve, reject);
            } else {
              resolve(res);
            }
          }
        } catch (err) {
          reject(err);
        }
      };
      // 封装一个失败时执行的函数
      const rejected = (reason) => {
        try {
          if (!isFunction(onRejected)) {
            reject(reason);
          } else {
            let x = onRejected(reason);
            if (x instanceof MyPromise) {
              x.then(resolve, reject);
            } else {
              resolve(x);
            }
          }
        } catch (err) {
          reject(err);
        }
      };
      switch (this._status) {
        case PENDING:
          this._fulfilledQueues.push(onFulfilled);
          this._rejectedQueues.push(onRejected);
          break;
        case FULFILLED:
          fulfilled(this._value);
          break;
        case REJECTED:
          rejected(this._value);
          break;
      }
    });
  }
}

export default MyPromise;
